/**
 * 
 */
package t4j.generics;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

interface Combiner<T> {
	T combine(T x,T y);
}

interface UnaryFunction<R,T>{
	R function(T x);
}

interface Collector<T> extends UnaryFunction<T, T>{
	T result();
}

interface UnaryPredicate<T> { 
	boolean test(T x); 
}

public class Functional {
	
	//循环执行combine()
	public static <T> T reduce(Iterable<T> seq,Combiner<T> combiner){
		Iterator<T> it = seq.iterator();
		
		if(it.hasNext()){
			T result = it.next();
			
			while(it.hasNext())
				result = combiner.combine(result, it.next());
			
			return result;
		}
		
		return null;
	}
	
	//循环执行function()
	public static <T> Collector<T> forEach(Iterable<T> seq,Collector<T> func){
		for(T t: seq)
			func.function(t);
		
		return func;//返回Collector对象
	}
	
	public static <R,T> List<R> transform(Iterable<T> seq,UnaryFunction<R, T> func){
		List<R> result = new ArrayList<R>();
		
		for(T t:seq)
			result.add(func.function(t));
		
		return result;
	}
	
	//循环执行test(),返回list
	public static <T> List<T> filter(Iterable<T> seq,UnaryPredicate<T> pred){
		List<T> result = new ArrayList<T>();
		
		for(T t: seq)
			if(pred.test(t))
				result.add(t);
		
		return result;
	}
	//策略模式
	static class IntegerAdder implements Combiner<Integer>{
		public Integer combine(Integer x, Integer y) {
			return x + y;
		}	
	}
	
	static class IntegerSubtracter implements Combiner<Integer>{
		public Integer combine(Integer x, Integer y) {
			return x - y;
		}
	}
	
	static class BigDecimalAdder implements Combiner<BigDecimal>{
		public BigDecimal combine(BigDecimal x, BigDecimal y) {
			return x.add(y);
		}
	}
	
	//BigInteger的加法
	static class BigIntegerAdder implements Combiner<BigInteger>{
		public BigInteger combine(BigInteger x, BigInteger y) {
			return x.add(y);//返回x+y
		}
	}
	
	static class AtomicLongAdder implements Combiner<AtomicLong>{
		public AtomicLong combine(AtomicLong x, AtomicLong y) {
			return new AtomicLong(x.addAndGet(y.get()));
		}
	}
	
	
	static class BigDecimalUlp implements UnaryFunction<BigDecimal, BigDecimal>{
		public BigDecimal function(BigDecimal x) {
			return x.ulp();//返回此 BigDecimal 的 ulp（最后一位的单位）的大小。
		}
	}
	
	//T的上边界是Comparable，Integer类是实现了Comparable接口的
	static class GreaterThan<T extends Comparable<T>> implements UnaryPredicate<T>{

		private T bound;
		
		public GreaterThan(T bound){
			this.bound = bound;
		}
		
		public boolean test(T x) {	
			return x.compareTo(bound) > 0;//拿x和bound比较，结果是-1,0,1
		}
	}
	
	//*
	static class MultiplyingIntegerCollector implements Collector<Integer>{
		private Integer val = 1;

		public Integer function(Integer x) {
			val *= x;
			return val;
		}
	
		public Integer result() {
			return val;
		}
	}
	
	public static void main(String[] args) {
		List<Integer> li = Arrays.asList(1,2,3,4,5,6,7);
		
		Integer result = reduce(li, new IntegerAdder());//+
		
		System.out.println(result);
		
		result = reduce(li, new IntegerSubtracter());//-
		
		System.out.println(result);
		
		System.out.println(	filter(li, new GreaterThan<Integer>(4)));//从4开始
		
		System.out.println(forEach(li, new MultiplyingIntegerCollector()).result());//*
		
		System.out.println(forEach(filter(li, new GreaterThan<Integer>(4))
				, new MultiplyingIntegerCollector()).result());//先获得大于4的数，再*
		
		MathContext mc = new MathContext(7);
		
		List<BigDecimal> lbd = Arrays.asList(new BigDecimal(1.1,mc),new BigDecimal(2.2,mc),
				new BigDecimal(3.3,mc),new BigDecimal(4.4,mc));
		
		BigDecimal rbd = reduce(lbd,new BigDecimalAdder());
		
		System.out.println(rbd);//?
		
		System.out.println(filter(lbd, new GreaterThan<BigDecimal>(new BigDecimal(3))));//大精度的过滤，输出3以上
		
		//从11开始打印11次，下一个素数
		List<BigInteger> lbi= new ArrayList<BigInteger>();
		
		BigInteger bi = BigInteger.valueOf(11);
		
		for(int i=0;i<11 ;i++){
			lbi.add(bi);
			bi = bi.nextProbablePrime();
		}
		
		System.out.println(lbi);
		
		BigInteger rbi = reduce(lbi, new BigIntegerAdder());//把上边的lbi加起来
		
		System.out.println(rbi);
		
		System.out.println(rbi.isProbablePrime(5));
		
		List<AtomicLong> lal = Arrays.asList(new AtomicLong(11),new AtomicLong(47)
											,new AtomicLong(74),new AtomicLong(113));
		
		AtomicLong ral = reduce(lal, new AtomicLongAdder());
		
		System.out.println(ral);
		
		System.out.println(transform(lbd, new BigDecimalUlp()));
	}
	
}
